﻿/*
 * Created by SharpDevelop.
 * User: mkrueger
 * Date: 25.03.2011
 * Time: 11:11
 * 
 * To change this template use Tools | Options | Coding | Edit Standard Headers.
 */
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Linq;
using System.IO;
using System.Text;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Interop;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Threading;
using System.Runtime.InteropServices;

using Chronicle.Analyzation;
using Chronicle.Modules;
using Chronicle.Parser;

namespace Chronicle.Gui
{
	/// <summary>
	/// Interaction logic for Window1.xaml
	/// </summary>
	public partial class MainWindow : Window
	{
		AnalyzeModule[] modules = new AnalyzeModule[] {
			new DamageModule(),
			new HealModule(),
			new DeathModule()
		};
		
		AnalyzeVisitor visitor = new AnalyzeVisitor ();
		CombatLogParser parser = new CombatLogParser ();
		Timer timer;
		StreamReader sr;
		
		AnalyzeModule module;
		AnalyzeModule Module {
			get { return module; }
			set {
				module = value;
				if (comboBoxEvents.SelectedIndex >= 0)
					UpdateEvents ();
			}
		}
		
		internal static Process GetRiftProcess ()
		{
			return Process.GetProcesses().Where (p => p.MainWindowTitle == "RIFT").FirstOrDefault ();
		}
		
		static string GetFileName (Process riftProcess)
		{
			if (riftProcess != null)
				return Path.Combine (Path.GetDirectoryName (riftProcess.MainModule.FileName), "CombatLog.txt");
			return null;
		}

		static StreamReader OpenReader ()
		{
			string fileName = GetFileName (GetRiftProcess ());
			if (fileName == null)
				return null;
			try {
				if (File.Exists (fileName))
					return new StreamReader(new FileStream (fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite));
			} catch (Exception) {
			}
			return null;
		}
		
		#region EventList
		List<EventList> eventList = new List<MainWindow.EventList> ();
		public List<EventList> EventCollection {
			get {
				return eventList;
			}
		}
		
		public class EventList
		{
			EventInformation info;
			
			public virtual EventInformation Info {
				get { return info; }
			}
			
			protected EventList ()
			{
			}

			public EventList(EventInformation info)
			{
				this.info = info;
			}

			public virtual string Text {
				get {
					TimeSpan duration = (info.EndTime - info.StartTime);
					return info.StartTime.ToShortTimeString () + ":" + info.EventName + " (" + duration.Minutes.ToString ("00") + ":" + duration.Seconds.ToString ("00") + ")";
				}
			}
		}
		
		class AllFightEventItem : EventList
		{
			AnalyzeVisitor visitor;
			
			public override EventInformation Info {
				get { return visitor.allEvents; }
			}
			
			public AllFightEventItem(AnalyzeVisitor visitor)
			{
				this.visitor = visitor;
			}
			
			public override string Text {
				get { return "All data"; }
			}
		}
		
		class CurrentEventItem : EventList
		{
			AnalyzeVisitor visitor;
			
			public override EventInformation Info {
				get { return visitor.curEvent; }
			}
			
			public CurrentEventItem(AnalyzeVisitor visitor)
			{
				this.visitor = visitor;
			}
			
			public override string Text {
				get { return "Current fight"; }
			}
		}
		#endregion
		
		#region DataList
		List<ActorData> actorCollection = new List<ActorData>();
		
		public List<ActorData> ActorCollection {
			get { return actorCollection; }
		}
		
		public class ActorData
		{
			Actor actor;
			AnalyzeModule module;
			EventInformation info;
			
			public Actor Actor {
				get { return actor; }
			}
			
			public ActorData(Actor actor, AnalyzeModule module, EventInformation info)
			{
				this.actor = actor;
				this.module = module;
				this.info = info;
			}
			
			public string Name {
				get {
					return actor.Name;
				}
			}
			
			public string Value {
				get {
					return module.GetHintText (info, actor);
				}
			}
		}
		
		public void UpdateEvent (EventInformation eventInfo)
		{
			DataContext = null;
			this.eventInformation = eventInfo;
			actorCollection.Clear ();
			if (eventInfo == null) {
				return;
			}
			foreach (var actor in eventInfo.Actors.Values) {
				if (actor.ActorType != ActorType.Player)
					continue;
				actorCollection.Add (new ActorData (actor, Module, eventInfo));
			}
			actorCollection.Sort ((a, b) => Module.Compare (b.Actor, a.Actor));
			DataContext = actorCollection;
		}
			
		void UpdateEvents ()
		{
			int idx = comboBoxEvents.SelectedIndex;
			if (idx >= 0 && idx < eventList.Count)
				UpdateEvent (eventList[idx].Info);
		}
		#endregion
		
		public MainWindow()
		{
			InitializeComponent();
			this.Topmost = true;
			foreach (var module in modules) {
				comboBoxModules.Items.Add (module.Name);
				module.Attach (visitor);
			}
			
			timer = new System.Threading.Timer (TimerCallBack, this, 0, 200);
			comboBoxModules.SelectionChanged += delegate { 
				Module = modules [comboBoxModules.SelectedIndex];
			};
			comboBoxModules.SelectedIndex = 0;
			
			(Resources["eventList"] as CollectionViewSource).Source = eventList;
			
			eventList.Add (new AllFightEventItem (visitor));
			eventList.Add (new CurrentEventItem (visitor));
			visitor.EventCreated += delegate(object sender, EventInformationEventArgs e) { eventList.Insert (2, new EventList(e.EventInformation)); };
			comboBoxEvents.SelectionChanged += delegate { 
				UpdateEvents ();
			};
			comboBoxEvents.SelectedIndex = 0;
			
			overviewListView.MouseDoubleClick += delegate {
				ActorData data = overviewListView.SelectedItem as ActorData;
				if (data == null)
					return;
				var window = new DetailsWindow (Module, data.Actor);
				window.Owner = this;
				window.Show ();
			};
		}
		
		EventInformation eventInformation;
		
		protected override void OnClosed(EventArgs e)
		{
			base.OnClosed(e);
			timer.Dispose();
			if (sr != null) {
				sr.Close ();
				sr = null;
			}
		}
		protected override void OnStateChanged(EventArgs e)
		{
			base.OnStateChanged(e);
			if (WindowState == WindowState.Minimized)
				WindowState = WindowState.Normal;
		}
		
		protected override void OnMouseLeave(MouseEventArgs e)
		{
			base.OnMouseLeave(e);
			var p = GetRiftProcess ();
			if (p != null)
				SetForegroundWindow (p.MainWindowHandle);
		}
		
		void TimerCallBack (object state)
		{
			this.Dispatcher.Invoke (DispatcherPriority.Normal, new Action (delegate {
				if (Visibility == Visibility.Hidden)
					return;
				
				if (sr == null) {
					sr = OpenReader ();
					if (sr == null)
						return;
					tabControl1.SelectedIndex = 1;
				}
				
				bool changed = false;
				try {
					while (sr != null && !sr.EndOfStream) {
						string line;
						line = sr.ReadLine();
						var evt = parser.Parse (line);
						
						if (evt == null)
							continue;
						
						evt.Accept (visitor);
						changed = true;
					}
				} catch (Exception e) {
					MessageBox.Show ("An error occured:" + e.ToString (), "Error");
					Close ();
					return;
				}
	
				if (changed)
					UpdateEvents();
			}));
		}
		
		
		[DllImport("user32.dll")]
 		[return: MarshalAs(UnmanagedType.Bool)]
 		internal static extern bool SetForegroundWindow(IntPtr hWnd);
	
 		[DllImport("user32.dll")]
		[return: MarshalAs(UnmanagedType.Bool)]
		static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, ulong uFlags);

		[DllImport("user32.dll")] 
 		static extern long SetParent(IntPtr hWnd, IntPtr hWnd2);
	
		static readonly IntPtr HWND_TOPMOST = new IntPtr(-1);
		static readonly IntPtr HWND_NOTOPMOST = new IntPtr(-2);
		static readonly IntPtr HWND_TOP = new IntPtr(0);
		static readonly IntPtr HWND_BOTTOM = new IntPtr(1);


		void button1_Click(object sender, RoutedEventArgs e)
		{
			if (this.WindowStyle == WindowStyle.None) {
				this.WindowStyle = WindowStyle.ToolWindow;
			} else {
				this.WindowStyle = WindowStyle.None;
			}
		}
		
		void button2_Click(object sender, RoutedEventArgs e)
		{
			visitor.Reset ();
			
			eventList.Clear ();
			eventList.Add (new AllFightEventItem (visitor));
			eventList.Add (new CurrentEventItem (visitor));
			comboBoxEvents.SelectedIndex = 0;
			
			UpdateEvents ();
		}
	}
}